/*
 *  Author: Charlie Welch
 *  Description: Sweet online videogame BITCH.
 *  Date Created: 02/11/2012
 */

#include <windows.h>
#include <stdarg.h>
#include <stdio.h>
#include <gl/gl.h>
#include <gl/glut.h>

LRESULT CALLBACK
WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
GLvoid glPrint(const char *fmt, ...);
GLvoid BuildFont(HDC *hDC);
VOID EnableOpenGL(HWND hWnd, HDC * hDC, HGLRC * hRC);
VOID DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC);

float x = 10;
float y = 10;
GLuint base;
bool key_down = false;
bool key_up = false;
bool key_right = false;
bool key_left = false;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow) {
    WNDCLASS wc;
    HWND hWnd;
    HDC hDC;
    HGLRC hRC;
    MSG msg;
    BOOL bQuit = FALSE;
    float theta = 0.0f;

    // register window class
    wc.style = CS_OWNDC;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "GLGame";
    RegisterClass(&wc);

    // create main window
    hWnd = CreateWindow("GLGame", "Sweet online Game", WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE,
        30, 30, 640, 480, NULL, NULL, hInstance, NULL);

    // enable OpenGL for the window
    EnableOpenGL( hWnd, &hDC, &hRC );
    glOrtho(0,640,480,0,0,1);

    float prevtime = timeGetTime();
    // program main loop
    while (!bQuit) {
        // check for messages
        if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            // handle or dispatch messages
            if(msg.message == WM_QUIT) {
                bQuit = TRUE;
            } else {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        } else {
            float time = timeGetTime();
            float deltatime = time - prevtime;
            prevtime = time;

            // OpenGL animation code goes here
            glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
            glClear(GL_COLOR_BUFFER_BIT);

            // key handles; 5px/sec is the square's speed
            if(key_down) {
                y += 0.15 * deltatime;
            }
            if(key_right) {
                x += 0.15 * deltatime;
            }
            if(key_left) {
                x -= 0.15 * deltatime;
            }
            if(key_up) {
                y -= 0.15 * deltatime;
            }

            glPushMatrix();
            glBegin(GL_LINE_LOOP);
                glColor3f(1.0f, 0.0f, 0.0f);glVertex2f(x, y);
                glColor3f(0.0f, 1.0f, 0.0f);glVertex2f(x+32, y);
                glColor3f(0.0f, 0.0f, 1.0f);glVertex2f(x+32, y+32);
                glColor3f(0.0f, 1.0f, 1.0f);glVertex2f(x, y+32);
            glEnd();
            glPopMatrix();
            
            glColor3f(0.0f, 0.0f, 0.0f);
            glRasterPos2i(0, 32);
            glPrint("Elapsed time: %.0fms", deltatime);
            
            SwapBuffers(hDC);

            theta += 1.0f;
        }
    }
    // shutdown OpenGL
    DisableOpenGL( hWnd, hDC, hRC );
    // destroy the window explicitly
    DestroyWindow( hWnd );
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
        case WM_CREATE:
            return 0;
        case WM_CLOSE:
            PostQuitMessage(0);
            return 0;
        case WM_DESTROY:
            return 0;
        case WM_KEYDOWN:
            switch(wParam) {
                case VK_ESCAPE:
                    PostQuitMessage(0);
                    return 0;
                case VK_UP:
                    if(!key_up) {
                        key_up = true;
                    }
                    return 0;
                case VK_DOWN:
                    if(!key_down) {
                        key_down = true;
                    }
                    return 0;
                case VK_LEFT:
                    if(!key_left) {
                        key_left = true;
                    }
                    return 0;
                case VK_RIGHT:
                    if(!key_right) {
                        key_right = true;
                    }
                    return 0;
            }
            return 0;
        case WM_KEYUP:
            switch(wParam) {
                case VK_DOWN:
                    key_down = false;
                    return 0;
                case VK_UP:
                    key_up = false;
                    return 0;
                case VK_LEFT:
                    key_left = false;
                    return 0;
                case VK_RIGHT:
                    key_right = false;
                    return 0;
            }
            return 0;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
}

GLvoid BuildFont(HDC hDC) {
	HFONT	font;
	HFONT	oldfont;
	base = glGenLists(96);
	font = CreateFont(-16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET,
    	OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_DONTCARE|DEFAULT_PITCH, "Courier New");

	oldfont = (HFONT)SelectObject(hDC, font);
	wglUseFontBitmaps(hDC, 32, 96, base);
	SelectObject(hDC, oldfont);
	DeleteObject(font);
}

// Custom GL "Print" Routine
GLvoid glPrint(const char *fmt, ...) {
	char text[256];
	va_list ap;

	if (fmt == NULL)
		return;

	va_start(ap, fmt);
	    vsprintf(text, fmt, ap);
	va_end(ap);

	glPushAttrib(GL_LIST_BIT);
	glListBase(base - 32);
	glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
	glPopAttrib();
}

VOID EnableOpenGL(HWND hWnd, HDC * hDC, HGLRC * hRC) {
    PIXELFORMATDESCRIPTOR pfd;
    int iFormat;

    // get the device context (DC)
    *hDC = GetDC(hWnd);

    // set the pixel format for the DC
    ZeroMemory(&pfd, sizeof(pfd));
    pfd.nSize = sizeof(pfd);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;
    pfd.cDepthBits = 16;
    pfd.iLayerType = PFD_MAIN_PLANE;
    iFormat = ChoosePixelFormat(*hDC, &pfd);
    SetPixelFormat(*hDC, iFormat, &pfd);

    // create and enable the render context (RC)
    *hRC = wglCreateContext(*hDC);
    wglMakeCurrent(*hDC, *hRC);
    
    BuildFont(*hDC);
}

VOID DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC) {
    wglMakeCurrent(NULL, NULL);
    wglDeleteContext(hRC);
    ReleaseDC(hWnd, hDC);
    glDeleteLists(base, 96);
}
